package com.onesports.intelligent.k12.polarlight.service.course;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.onesports.intelligent.k12.polarlight.common.errors.exceptions.BusinessException;
import com.onesports.intelligent.k12.polarlight.constant.CodeConstants;
import com.onesports.intelligent.k12.polarlight.domain.dto.course.ClassMergeRuleIdAndPriceDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.course.CourseDetailDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.course.CourseManagePageDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.course.CourseManegeSaveOrUpdateDTO;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.*;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.Product;
import com.onesports.intelligent.k12.polarlight.domain.entity.organization.CoachCourseRel;
import com.onesports.intelligent.k12.polarlight.domain.vo.common.IdToNameVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.CourseDetailPageVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.CourseDetailVo;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.CourseGuidePriceRelVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.CourseVO;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseAdjustPriceRecordMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseScheduleMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseSellPriceRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.organization.CoachCourseRelMapper;
import com.onesports.intelligent.k12.polarlight.service.cls.ClassMergeRuleService;
import com.onesports.intelligent.k12.polarlight.service.course.manage.CourseClassifyService;
import com.onesports.intelligent.k12.polarlight.service.course.manage.CourseGuidePriceRelService;
import com.onesports.intelligent.k12.polarlight.service.course.manage.CourseOpenService;
import com.onesports.intelligent.k12.polarlight.service.course.manage.CourseSubLevelService;
import com.onesports.intelligent.k12.polarlight.service.sys.ProductService;
import com.onesports.intelligent.k12.polarlight.util.CodeUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author FPH
 * @since 2022年7月10日13:05:05
 */
@Service
@RequiredArgsConstructor
public class CourseManageService {
    private static final Logger log = LoggerFactory.getLogger(CourseManageService.class);

    private final CourseService courseService;

    private final CourseClassifyService courseClassifyService;

    private final CourseSubLevelService courseSubLevelService;

    private final ClassMergeRuleService classMergeRuleService;

    private final CourseGuidePriceRelService courseGuidePriceRelService;

    private final CourseOpenService courseOpenService;

    private final ProductService productService;

    private final CodeUtils codeUtils;

    private final CourseSellPriceRelMapper courseSellPriceRelMapper;

    private final CourseScheduleMapper courseScheduleMapper;

    private final CoachCourseRelMapper coachCourseRelMapper;

    private final CourseAdjustPriceRecordMapper courseAdjustPriceRecordMapper;
    /**
     * 根据条件分页查询
     * @param dto
     * @return
     */
    public IPage<CourseVO> queryCoursePage(CourseManagePageDTO dto){

        Page<Course> page = new Page<>(dto.getPage(),dto.getRow());
        Page<CourseVO> resultPage = new Page<>();

        Page<Course> coursePage = courseService.page(page, new LambdaQueryWrapper<Course>()
                .like(StringUtils.isNotEmpty(dto.getCourseName()), Course::getCourseName, dto.getCourseName())
                .eq(StringUtils.isNotEmpty(dto.getClassifyId()), Course::getCourseClassifyId, dto.getClassifyId())
                .eq(StringUtils.isNotEmpty(dto.getSubLevelId()), Course::getCourseSubLevelId, dto.getSubLevelId())
                .eq(Course::getDeleted,false)
                .orderByDesc(Course::getCreatedDate));
        BeanUtils.copyProperties(page,resultPage,"records");

        //course集合
        List<Course> courseList = coursePage.getRecords();
        if(CollectionUtils.isEmpty(courseList)){
            return new Page<>(dto.getPage(),dto.getRow());
        }

        ArrayList<CourseVO> courseQueryVOS = new ArrayList<>();
        //分类ID与分类名称关系集合
        List<IdToNameVO> classifyIdList = courseClassifyService.list(new LambdaQueryWrapper<CourseClassify>()
                        .in(CourseClassify::getId, courseList
                                .stream()
                                .map(Course::getCourseClassifyId)
                                .collect(Collectors.toList())))
                .stream().map(i -> {
                    IdToNameVO vo = new IdToNameVO();
                    vo.setId(i.getId());
                    vo.setName(i.getClassifyName());
                    return vo;
                }).collect(Collectors.toList());

        //分阶ID与分阶名称、年龄关系集合

        List<IdToNameVO> subLevelIdList = courseSubLevelService.list(new LambdaQueryWrapper<CourseSubLevel>()
                        .in(CourseSubLevel::getId,courseList
                                .stream()
                                .map(Course::getCourseSubLevelId)
                                .collect(Collectors.toList())))
                .stream().map(i -> {
                    IdToNameVO vo = new IdToNameVO();
                    vo.setId(i.getId());
                    vo.setName(i.getSubLevelName());
                    vo.setMaxAge(i.getMaxAge());
                    vo.setMinAge(i.getMinAge());
                    return vo;
                }).collect(Collectors.toList());

        //拼版班级及指导价集合
        List<CourseGuidePriceRelVO> classMergeRules = courseService.queryClassMergeRuleByIds(courseList
                .stream().map(Course::getId).collect(Collectors.toList()));
        courseList.forEach(i->{
            CourseVO courseVO = new CourseVO();
            BeanUtils.copyProperties(i,courseVO);
            courseVO.setCourseId(i.getId());

            //分类
            IdToNameVO classifyId = classifyIdList
                    .stream()
                    .filter(id -> id.getId().equals(i.getCourseClassifyId()))
                    .findFirst().orElseThrow(()->new BusinessException("传入的分类ID异常"));
            courseVO.setClassifyName(classifyId.getName());
            courseVO.setClassifyId(classifyId.getId());

            //分阶
            IdToNameVO subLevelId = subLevelIdList
                    .stream()
                    .filter(id -> id.getId().equals(i.getCourseSubLevelId()))
                    .findFirst().orElseThrow(()->new BusinessException("分阶ID不正确"));

            courseVO.setSubLevelName(subLevelId.getName());
            courseVO.setSubLevelId(subLevelId.getId());
            //年龄
            courseVO.setMaxAge(subLevelId.getMaxAge());
            courseVO.setMinAge(subLevelId.getMinAge());
            //拼班班型及指导价
            List<CourseGuidePriceRelVO> classMergeRuleList = classMergeRules.stream().filter(list -> list.getCourseId().equals(i.getId())).collect(Collectors.toList());
            courseVO.setGuidePriceRel(classMergeRuleList);
            courseVO.setCreatedDate(convertInstant(i.getCreatedDate()));
            courseVO.setLastModifiedDate(convertInstant(i.getLastModifiedDate()));
            courseQueryVOS.add(courseVO);
        });

        resultPage.setRecords(courseQueryVOS);
        return resultPage;
    }

    /**
     * 将Instant类型转为date
     * @param instant
     * @return
     */
    public Date convertInstant(Instant instant){
        if(instant==null){
            return null;
        }
        try {
            return new Date(instant.toEpochMilli());
        }catch (Exception e){
            throw new BusinessException(e.getMessage()+"时间转化失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean saveOrUpdate(CourseManegeSaveOrUpdateDTO courseManegeSaveOrUpdateDTO){
        CourseManegeSaveOrUpdateDTO dto = courseService.checkId(courseManegeSaveOrUpdateDTO);

        //course表
        Course course = new Course();
        BeanUtils.copyProperties(dto,course);
        //校验名称是否重复
        if(Boolean.FALSE.equals(courseService.checkName(course))){
            throw new BusinessException("名称重复");
        }
        //校验分阶分类是否在同一树下
        if (Boolean.FALSE.equals(courseSubLevelService.checkClassifyAndLevel(dto.getCourseClassifyId(),dto.getCourseSubLevelId()))) {
            throw new BusinessException("分阶分类关系异常");
        }

        //生成课程编码
        if(StringUtils.isEmpty(dto.getId())){
            String classifyCode = courseClassifyService.getById(dto.getCourseClassifyId()).getClassifyCode();
            String randomCode = codeUtils.autoSerialNumberNoPrefix(CodeConstants.COURSE_CODE+classifyCode, 3);
            course.setCourseCode(classifyCode+randomCode);
        }else {
            checkOperation(dto.getId());
        }

        //修改or插入主表
        courseService.saveOrUpdate(course);

        //通过排版规则ID校验是否存在此数据，存在则查询出此数据
        List<String> classMergeRuleIdList = dto.getClassMergeRuleIdAndPriceList()
                .stream()
                .map(ClassMergeRuleIdAndPriceDTO::getId)
                .collect(Collectors.toList());
        List<ClassMergeRule> classMergeRuleList = classMergeRuleService.list(new LambdaQueryWrapper<ClassMergeRule>()
                .in(ClassMergeRule::getId, classMergeRuleIdList));

        if(CollectionUtils.isEmpty(classMergeRuleList)||classMergeRuleList.size()!=dto.getClassMergeRuleIdAndPriceList().size()){
            throw new BusinessException("拼班规则信息存在异常");
        }

        //插入course_guide_price_rel表
        //移除所有子表
        courseGuidePriceRelService.removeByCourseId(course.getId());

        ArrayList<CourseGuidePriceRel> courseGuidePriceRels = new ArrayList<>();

        dto.getClassMergeRuleIdAndPriceList().forEach(i->{
            CourseGuidePriceRel courseGuidePriceRel = new CourseGuidePriceRel();

            ClassMergeRule classMergeRule = classMergeRuleList
                    .stream().filter(list -> list.getId().equals(i.getId()))
                    .findFirst().orElse(null);
            BeanUtils.copyProperties(classMergeRule,courseGuidePriceRel,"id","createdBy","createdDate");
            courseGuidePriceRel.setCourseId(course.getId());
            courseGuidePriceRel.setPrice(i.getPrice());
            courseGuidePriceRel.setMergeRuleId(i.getId());
            courseGuidePriceRels.add(courseGuidePriceRel);
        });
        if(Boolean.FALSE.equals(courseGuidePriceRelService.saveBatch(courseGuidePriceRels))){
            throw new BusinessException("courseGuidePriceRel插入失败");
        }
        //重置校区售价表
        courseService.initCourseSellPrice(course.getId(), courseGuidePriceRels);
        return true;
    }

    /**
     * 通用删除
     * @param id 课程管理ID
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(String id){
        Course course = courseService.getById(id);
        if(course==null||course.getDeleted()){
            throw new BusinessException("传入的ID不存在");
        }
        checkOperation(id);
        //真删除
        courseService.removeById(id);
        //删除指导价关联表
        courseGuidePriceRelService.removeByCourseId(id);
        //删除社区课程售价
        courseSellPriceRelMapper.delete(new LambdaQueryWrapper<CourseSellPriceRel>().eq(CourseSellPriceRel::getCourseId,id));
        return true;
    }

    /**
     * 校验删除与修改是否执行
     * @param id
     */
    void checkOperation(String id){
        checkProduct(id);
        checkScheduleDate(id);
        checkCourseOpen(id);
        checkCoachCourseRel(id);
        checkAdjustPriceRecord(id);
    }

    /**
     * 判断是否存在调价记录
     * @param courseId
     */
    void checkAdjustPriceRecord(String courseId){
        List<CourseAdjustPriceRecord> courseAdjustPriceRecords = courseAdjustPriceRecordMapper.selectList(new LambdaQueryWrapper<CourseAdjustPriceRecord>()
                .eq(CourseAdjustPriceRecord::getCourseId, courseId)
                .eq(CourseAdjustPriceRecord::getAuditStatus,"1"));
        if(CollectionUtils.isNotEmpty(courseAdjustPriceRecords)){
            throw new BusinessException("存在调价记录，无法操作");
        }
    }

    /**
     * 校验教练课程是否关联
     * @param courseId
     */
    void checkCoachCourseRel(String courseId){
        List<CoachCourseRel> coachCourse = coachCourseRelMapper.selectList(new LambdaQueryWrapper<CoachCourseRel>().eq(CoachCourseRel::getCourseId, courseId));
        if(CollectionUtils.isNotEmpty(coachCourse)){
            throw new BusinessException("教练与课程已关联，无法操作");
        }
    }


    /**
     * 检查当前日期是否在课表的计划时间之内，如果存在于课表时间内，则不允许删除
     * @param courseId
     */
    public void checkScheduleDate(String courseId){
        LocalDateTime now = LocalDateTime.now();
        Date from = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
        List<CourseSchedule> courseSchedules = courseScheduleMapper
                .selectList(new LambdaQueryWrapper<CourseSchedule>()
                        .eq(CourseSchedule::getCourseId, courseId)
                        .le(CourseSchedule::getStartDate,from)
                        .ge(CourseSchedule::getEndDate,from));
        if(CollectionUtils.isNotEmpty(courseSchedules)){
            throw new BusinessException("存在当前日期在排课范围内对应的课程");
        }
    }

    /**
     * 查询课程开设时间表是否存在此数据
     * @param id
     */
    public void checkCourseOpen(String id){
        List<CourseOpen> courseOpenList = courseOpenService.list(new LambdaQueryWrapper<CourseOpen>()
                .eq(CourseOpen::getCourseId, id));
        if(CollectionUtils.isNotEmpty(courseOpenList)){
            throw new BusinessException("该课程已排课");
        }
    }

    /**
     * 校验是否为商品
     * @param courseId
     */
    public void checkProduct(String courseId){
        List<Product> list = productService.list(new LambdaQueryWrapper<Product>().eq(Product::getCourseId, courseId));
        if(CollectionUtils.isNotEmpty(list)){
            throw new BusinessException("该课程已被添加为商品不允许操作");
        }
    }

    /**
     * 根据ID回显数据
     * @param id
     * @return
     */
    public CourseDetailVo queryDetailById(String id){
        CourseDetailVo courseDetailVo = new CourseDetailVo();
        //根据ID查询NAME
        Course course = courseService.getById(id);
        if(course==null||course.getDeleted()){
            return null;
        }
        CourseManagePageDTO courseManagePageDTO = new CourseManagePageDTO();
        courseManagePageDTO.setPage(1);
        courseManagePageDTO.setRow(Long.MAX_VALUE);
        courseManagePageDTO.setCourseName(course.getCourseName());
        CourseVO collect = queryCoursePage(courseManagePageDTO).getRecords().stream()
                .filter(list -> id.equals(list.getCourseId()))
                .findFirst().orElse(null);
        BeanUtils.copyProperties(course,courseDetailVo);

        BeanUtils.copyProperties(collect,courseDetailVo);

        return courseDetailVo;
    }

    /**
     * 通过模板获取mergeRuleId
     * @param dto
     * @return
     */
    public IPage<CourseDetailPageVO> getDetail(CourseDetailDTO dto){
        Page<CourseDetailPageVO> page = new Page<>(dto.getPage(), dto.getRow());
        return courseSellPriceRelMapper.getByCourseIdAndPriceId(page,dto.getCourseId(),dto.getMergeRuleId());
    }
}
